package com.ynb.lighterbuffer;

import java.io.IOException;
import java.nio.charset.Charset;

public abstract class BinaryReader {

	private Charset utf8 = Charset.forName("utf8");

	public abstract byte readByte() throws IOException;

	public abstract byte[] readBytes(int len) throws IOException;

	public boolean readBool() throws IOException {
		return readByte() == 1 ? true : false;
	}

	public short readShort() throws IOException {
		short n = 0;
		n |= readByte();
		n |= (readByte() << 8);
		return n;
	}

	public int readInt() throws IOException {
		int v0 = readByte() & 0b11111111;
		if ((v0 & 0b01000000) == 0) {
			int v = 0;
			v |= (v0 & 0b00111111);
			if ((v0 & 0b10000000) == 0) {
				return v | ~0b00111111;
			} else {// continue
				int i = 1;
				while (true) {
					v0 = readByte();
					v |= ((v0 & 0b01111111) << ((i - 1) * 7 + 6));
					if ((v0 & 0b10000000) == 0) {
						if (i < 4) {
							return v | (~0b0 << (i * 7 + 6));
						} else {
							return v;
						}
					}
					i++;
				}
			}
		} else {
			int v = 0;
			v |= (v0 & 0b00111111);
			if ((v0 & 0b10000000) == 0) {
				return v;
			} else {// continue
				int i = 0;
				while (true) {
					v0 = readByte();
					v |= ((v0 & 0b01111111) << (i * 7 + 6));
					if ((v0 & 0b10000000) == 0) {
						return v;
					}
					i++;
				}
			}
		}
	}

	public long readLong() throws IOException {
		long v0 = readByte() & 0b11111111;
		if ((v0 & 0b01000000) == 0) {
			long v = 0;
			v |= (v0 & 0b00111111);
			if ((v0 & 0b10000000) == 0) {
				return v | ~0b00111111L;
			} else {// continue
				int i = 1;
				while (true) {
					v0 = readByte();
					v |= ((v0 & 0b01111111L) << ((i - 1) * 7 + 6));
					if ((v0 & 0b10000000) == 0) {
						if (i < 9) {
							return v | (~0b0L << (i * 7 + 6));
						} else {
							return v;
						}
					}
					i++;
				}
			}
		} else {
			long v = 0;
			v |= (v0 & 0b00111111);
			if ((v0 & 0b10000000) == 0) {
				return v;
			} else {// continue
				int i = 0;
				while (true) {
					v0 = readByte();
					v |= ((v0 & 0b01111111L) << (i * 7 + 6));
					if ((v0 & 0b10000000) == 0) {
						return v;
					}
					i++;
				}
			}
		}
	}

	public float readFloat() throws IOException {
		int v = 0;
		v |= (readByte() & 0b11111111);
		v |= (readByte() & 0b11111111) << 8;
		v |= (readByte() & 0b11111111) << 16;
		v |= (readByte() & 0b11111111) << 24;
		return Float.intBitsToFloat(v);
	}

	public double readDouble() throws IOException {
		long v = 0;
		v |= (readByte() & 0b11111111L);
		v |= (readByte() & 0b11111111L) << 8;
		v |= (readByte() & 0b11111111L) << 16;
		v |= (readByte() & 0b11111111L) << 24;
		v |= (readByte() & 0b11111111L) << 32;
		v |= (readByte() & 0b11111111L) << 40;
		v |= (readByte() & 0b11111111L) << 48;
		v |= (readByte() & 0b11111111L) << 56;
		return Double.longBitsToDouble(v);
	}

	public char readChar() throws IOException {
		return (char) readInt();
	}

	public String readString() throws IOException {
		int len = readInt();
		if (len > 0) {
			return new String(readBytes(len), utf8);
		} else if (len == 0) {
			return "";
		} else {
			return null;
		}
	}

	public short[] readShortArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			short[] arr = new short[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readShort();
			}
			return arr;
		}
	}

	public Short[] readShortObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Short[] arr = new Short[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readShort();
			}
			return arr;
		}
	}

	public int[] readIntArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			int[] arr = new int[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readInt();
			}
			return arr;
		}
	}

	public Integer[] readIntObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Integer[] arr = new Integer[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readInt();
			}
			return arr;
		}
	}

	public long[] readLongArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			long[] arr = new long[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readLong();
			}
			return arr;
		}
	}

	public Long[] readLongObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Long[] arr = new Long[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readLong();
			}
			return arr;
		}
	}

	public Float[] readFloatObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Float[] arr = new Float[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readFloat();
			}
			return arr;
		}
	}

	public double[] readDoubleArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			double[] arr = new double[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readDouble();
			}
			return arr;
		}
	}

	public Double[] readDoubleObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Double[] arr = new Double[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readDouble();
			}
			return arr;
		}
	}

	public Boolean[] readBoolObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Boolean[] arr = new Boolean[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readBool();
			}
			return arr;
		}
	}

	public String[] readStringArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			String[] arr = new String[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readString();
			}
			return arr;
		}
	}

	public Character[] readCharObjArr() throws IOException {
		int len = readInt();
		if (len < 0) {
			return null;
		} else {
			Character[] arr = new Character[len];
			for (int i = 0; i < len; i++) {
				arr[i] = readChar();
			}
			return arr;
		}
	}

	public boolean readNull() throws IOException{
		return readBool();
	}
	
}
